﻿namespace Refunctor

open System
open System.Text
open System.Windows
open System.Windows.Controls
open System.Windows.Input
open System.Windows.Data
open System.Windows.Media
open System.Windows.Media.Imaging
open Microsoft.Win32
open System.IO
open System.Diagnostics
open System.Collections.Concurrent
open System.Collections.Generic
open System.Text.RegularExpressions

[<AutoOpen>]
module ProgramPadOptionDialog = 

    type ProgramPadOptionDialog (defaultValue : ProgramEditorOption) as self=
        inherit Window(Title = "Options", WindowStyle = WindowStyle.ToolWindow, WindowStartupLocation = WindowStartupLocation.CenterScreen, Width = 640., Height = 540.,
                        ShowInTaskbar = true, SnapsToDevicePixels = true, ResizeMode = ResizeMode.NoResize, FontSize = 12.)

        let rootGrid = new Grid(Margin=Thickness(10.,10.,10.,10.))        
        let compilerOptionsText = new TextBox(MaxLength = 500, Width = 400.0, Height = 25., FontWeight = FontWeights.Normal, TabIndex = 1,
                                         ToolTip = "The command line arguments passed to fsc.exe.")
        let fscPathText = new TextBox(MaxLength = 500, Width = 400.0, Height = 25., FontWeight = FontWeights.Normal, TabIndex = 2,
                                      ToolTip="The path to fsc.exe.")
        let fscPathButton = new Button(Content="...", Height = 25., Width = 30., Margin = Thickness(5.,0.,0.,0.), FontWeight = FontWeights.Normal,
                                        TabIndex = 3)
        let sourceFilePathText = new TextBox(MaxLength = 500, Width = 400.0, Height = 25., FontWeight = FontWeights.Normal, TabIndex = 4,
                                      ToolTip="The path to save the current program file.")
        let saveFilePathButton = new Button(Content="...", Height = 25., Width = 30., Margin = Thickness(5.,0.,0.,0.), FontWeight = FontWeights.Normal,
                                        TabIndex = 5)
        let outputPathText = new TextBox(MaxLength = 500, Width = 400.0, Height = 25., FontWeight = FontWeights.Normal, TabIndex = 4,
                                      ToolTip="The path to save the compiled output of current program file.")
        let outputPathButton = new Button(Content="...", Height = 25., Width = 30., Margin = Thickness(5.,0.,0.,0.), FontWeight = FontWeights.Normal,
                                        TabIndex = 5)
        let loadToReflectorAfterBuildChkBox = new CheckBox(Content = "Load output assembly into Reflector after building", Margin = Thickness(150.,0.,0.,0.), FontWeight = FontWeights.Normal, HorizontalAlignment = HorizontalAlignment.Left)        
        let errorLabel = new Label(FontSize = 10.0, Height = 25., FontWeight = FontWeights.Normal, HorizontalAlignment = HorizontalAlignment.Left, Margin = Thickness(5.,0.,10.,0.), Foreground = Brushes.Red)

        let resetButton = new Button(Content = "Reset", Height = 25., Width = 80., HorizontalAlignment = HorizontalAlignment.Left)
        let okButton = new Button(Content = "OK", Height = 25., Width = 80., HorizontalAlignment = HorizontalAlignment.Left, Margin = new Thickness(5.,0.,0.,0.), IsDefault = true )
        let cancelButton = new Button(Content = "Cancel", Height = 25., Width = 80., HorizontalAlignment = HorizontalAlignment.Left, Margin = new Thickness(5.,0.,0.,0.), IsCancel = true)
        let editorConfigPad = new EditorConfig(defaultValue.EditorOption)
        let mutable setting = defaultValue
        let mutable optionDialogResult = DialogResult.Cancel

        let setFscPath() =            
            let dialog = new OpenFileDialog() 
            dialog.DefaultExt <- ".exe"
            dialog.Filter <- "fsc|fsc.exe"             
            dialog.RestoreDirectory <- true
            let r = dialog.ShowDialog()
            if r.HasValue && r.Value = true  then  
               fscPathText.Text <- dialog.FileName
        
        
            
        let buildProgramOptionGruop () =
            let group = new GroupBox(Header = "Program Options", FontSize = 11.5, FontWeight = FontWeights.SemiBold)
            let grid = new Grid()
            [1..5] |> List.iter (fun _ -> grid.RowDefinitions.Add(RowDefinition(Height=GridLength(0.0,GridUnitType.Auto))))            
            
            let sp1 = new StackPanel(Orientation = Orientation.Horizontal, Margin = new Thickness(5.,5.,0.,0.))
            Grid.SetRow(sp1,0)            
            sp1.Children.Add(Label(Content="F# Compiler Startup:", Width = 150.0, FontWeight = FontWeights.Normal) :> UIElement) |> ignore
            sp1.Children.Add(compilerOptionsText :> UIElement) |> ignore            
            grid.Children.Add(sp1) |> ignore

            let sp2 = new StackPanel(Orientation = Orientation.Horizontal, Margin = new Thickness(5.,5.,0.,0.))
            Grid.SetRow(sp2,1)            
            sp2.Children.Add(Label(Content="F# Compiler Path:", Width = 150.0, FontWeight = FontWeights.Normal) :> UIElement) |> ignore
            sp2.Children.Add(fscPathText :> UIElement) |> ignore
            fscPathButton.Click.Add(fun _  -> setFscPath())
            sp2.Children.Add(fscPathButton) |> ignore
            grid.Children.Add(sp2) |> ignore            

            let sp3 = new StackPanel(Orientation = Orientation.Horizontal, Margin = new Thickness(5.,5.,0.,0.))
            Grid.SetRow(sp3,2)            
            sp3.Children.Add(Label(Content="Source File Path:", Width = 150.0, FontWeight = FontWeights.Normal) :> UIElement) |> ignore
            sp3.Children.Add(sourceFilePathText :> UIElement) |> ignore    
            saveFilePathButton.Click.Add(fun _ ->  match getFolderPath() with Some(a) -> sourceFilePathText.Text <- a | _ -> ())                                                                                                                                                                          
            sp3.Children.Add(saveFilePathButton) |> ignore
            grid.Children.Add(sp3) |> ignore            
            
            let sp4 = new StackPanel(Orientation = Orientation.Horizontal, Margin = new Thickness(5.,5.,0.,0.))
            Grid.SetRow(sp4,3)            
            sp4.Children.Add(Label(Content="Output File Path:", Width = 150.0, FontWeight = FontWeights.Normal) :> UIElement) |> ignore
            sp4.Children.Add(outputPathText :> UIElement) |> ignore
            outputPathButton.Click.Add(fun _ -> match getFolderPath() with Some(a) -> outputPathText.Text <- a | _ -> ())
            sp4.Children.Add(outputPathButton) |> ignore
            grid.Children.Add(sp4) |> ignore
                                   
            let sp5 = new StackPanel(Orientation = Orientation.Horizontal, Margin = new Thickness(5.,5.,0.,0.))
            Grid.SetRow(sp5,4)                                                                      
            sp5.Children.Add(loadToReflectorAfterBuildChkBox) |> ignore
            grid.Children.Add(sp5) |> ignore

            group.Content <- grid
            group                     

        do
            rootGrid.RowDefinitions.Add(RowDefinition(Height=GridLength(0.0,GridUnitType.Auto)))
            rootGrid.RowDefinitions.Add(RowDefinition(Height=GridLength(1.0,GridUnitType.Star)))
            rootGrid.RowDefinitions.Add(RowDefinition(Height=GridLength(0.0,GridUnitType.Auto)))
            rootGrid.RowDefinitions.Add(RowDefinition(Height=GridLength(0.0,GridUnitType.Auto)))

            let programOptionGroup = buildProgramOptionGruop()
            Grid.SetRow(programOptionGroup,0)
            rootGrid.Children.Add(programOptionGroup) |> ignore

            Grid.SetRow(editorConfigPad,1)
            rootGrid.Children.Add(editorConfigPad) |> ignore

            let rectangle = new System.Windows.Shapes.Rectangle(StrokeThickness = 1., Stroke = Brushes.Silver, Margin = Thickness(0.,7.,0.,5.))
            Grid.SetRow(rectangle,2)
            rootGrid.Children.Add(rectangle) |> ignore

            let sp = new StackPanel(Orientation = Orientation.Horizontal, Margin = new Thickness(0.,5.,0.,5.), HorizontalAlignment = HorizontalAlignment.Right)
            Grid.SetRow(sp,3)
            sp.Children.Add(errorLabel) |> ignore
            resetButton.Click.Add(fun e ->
                                    optionDialogResult <- DialogResult.Reset
                                    self.Close()
                                 )
            sp.Children.Add(resetButton) |> ignore
            okButton.Click.Add(fun e ->    
                                if not <| File.Exists(fscPathText.Text.Trim()) then
                                    errorLabel.Content <- "The given F# compiler path is not found!"
                                elif not <| FileUtility.isValidPath(outputPathText.Text.Trim()) then
                                    errorLabel.Content <- "Output File Path is invalid or doesn't exist!"
                                elif not <| FileUtility.isValidPath(sourceFilePathText.Text.Trim()) then
                                    errorLabel.Content <- "Source File Path is invalid or doesn't exist!"
                                else
                                    setting <- {
                                                    FSCOptions  = match String.IsNullOrWhiteSpace <| compilerOptionsText.Text with
                                                                  | true -> ProgramEditorOption.DefaultFscOption
                                                                  | _ -> compilerOptionsText.Text.Trim()
                                                    FSCPath = match String.IsNullOrWhiteSpace <| fscPathText.Text with
                                                              | true -> ProgramEditorOption.DefaultFscPath
                                                              | _ -> fscPathText.Text.Trim()   
                                                    SourceFilePath = match String.IsNullOrWhiteSpace <| sourceFilePathText.Text with
                                                                     | true -> ProgramEditorOption.DefaultSaveFilePath
                                                                     | _ -> sourceFilePathText.Text.Trim()                                                                                      
                                                    OutputPath = match String.IsNullOrWhiteSpace <| outputPathText.Text with
                                                                   | true -> ProgramEditorOption.DefaultOutputPath
                                                                   | _ -> outputPathText.Text.Trim()
                                                         
                                                    LoadToReflectorAfterBuild = loadToReflectorAfterBuildChkBox.IsChecked.Value                                                                      
                                                    EditorOption = Option.get editorConfigPad.Settings
                                                }
                                    optionDialogResult <- DialogResult.OK
                                    self.Close())
            sp.Children.Add(okButton) |> ignore
            cancelButton.Click.Add(fun e ->
                                    optionDialogResult <- DialogResult.Cancel
                                    self.Close()
                                   )
            sp.Children.Add(cancelButton) |> ignore
            rootGrid.Children.Add(sp) |> ignore
           
            compilerOptionsText.Text <- defaultValue.FSCOptions
            fscPathText.Text <- defaultValue.FSCPath
            sourceFilePathText.Text <- defaultValue.SourceFilePath
            outputPathText.Text <- defaultValue.OutputPath
            loadToReflectorAfterBuildChkBox.IsChecked <- Nullable(defaultValue.LoadToReflectorAfterBuild)

            self.Content <- rootGrid

        member self.Settings with get() = setting
        member self.DialogResult with get() = optionDialogResult